//08290016
#include "ctcpserver.hpp"
#include "api.hpp"
#include <list>

using json = nlohmann::json;
using namespace std;

struct SockInfo infos[512];
void *working(void *arg);

bool debug_Mode = false;

map<string, long int> onlineUser;
map<string, file_transmit_t> userTemp;
list<json> userOperList;

int maxlen = 1024;

void ProcessingPackage(string package, int fd)
{
    json params;
    // 获取命令
    uint16_t command = ((((uint16_t)package[1]) << 8) & 0xFF00) + (((uint16_t)package[2]) & 0x00FF);
    //memcpy(&command,&(package[1]),2);
    printf("0x%02x\n", command);
    // 处理
    string content = package.substr(5, package.length() - 6);
    // 解包
    if (command >= 0x00FF && command <= 0x07FF)
    {
        pServerSaveFile(fd, content, command);
    }
    else
    {
        try
        {
            params = json::parse(content);
        }
        catch (...)
        {
            cout << "params error!\n";
        }
        // 登录检测
        bool online = false;
        if (command != 0x04 && command != 0x05)
        {
            if (!params.is_null() && params["UID"] != "")
            {
                try
                {
                    if (onlineUser.count(params["UID"]) != 0)
                        online = true;
                }
                catch (...)
                {
                    cout << "unknown errors\n";
                }
            }
        }
        try
        {
            if (!online && command != 0x04 && command != 0x05)
            {
                pRelogin(fd, params);
            }
            else
            {
                if (command != 0x04 && command != 0x05 && onlineUser.count(params["UID"]) != 0)
                    onlineUser[params["UID"]] = time(0);
                
                
                if (command >= 0x0800 && command <= 0xFFFF)
                {
                    pGetNextPieceFile(fd, params);
                }
                else{
                    switch (command)
                    {
                    case 0x01:
                        pHeartBeat(fd, params);
                        break;
                    case 0x04:
                        pRegister(fd, params);
                        break;
                    case 0x05:
                        pLogin(fd, params);
                        break;
                    case 0x06:
                        pSendMessage(fd, params);
                        break;
                    case 0x07:  
                        pSaveFileMessage(fd,params);              
                        break;
                    case 0x08:  
                        pEndServerSaveFile(fd,params);           
                        break;
                    case 0x09:  
                        pStartGetFile(fd, params);           
                        break;
                    case 0x0B:  
                        pSaveIcon(fd,params);            
                        break;
                    default:
                        sendPackage(string("unknown message"), 0x5B, fd);
                        break;
                    }
                    
                }
            }
        }
        catch (...)
        {
            cout << "process error\n";
        }
    }
    return;
}

void *working(void *arg)
{
    struct SockInfo *pinfo = (struct SockInfo *)arg;
    cout << "客户端已连接" << pinfo->addr << ")\n";
    string buffer;
    while (true)
    {
        buffer.clear();
        // 清空容器。
        buffer.resize(maxlen);                                       // 设置容器的大小为maxlen。
        int readn = ::recv(pinfo->fd, &buffer[0], buffer.size(), 0); // 直接操作buffer的内存。
        if (readn <= 0)
        {
            perror("recv()");
            break;
        }
        if (readn <= 5)
        {
            continue;
        }
        for (int i = 0; i < readn; i++)
            printf("%x ", buffer[i]);
        printf("\n");
        string package = GetValidData(buffer, readn);
        if (package == "")
        {
            sendString(string("The data packet does not meet the standard or is damaged\n"), pinfo->fd);//TODO:传1000个字符过来会进这里
            continue;
        }
        buffer.resize(readn); // 重置buffer的实际大小。
        cout << "接收：" << buffer << endl;
        ProcessingPackage(package, pinfo->fd);
        // cout << "发送" << buffer << endl;
    }
    ::close(pinfo->fd);
}

void *DetectOnlineUser(void *arg)
{
    while (true)
    {
        // cout<<"rundet\n";
        long int now_time = time(0);
        for (auto user : onlineUser)
        {
            cout << user.first << "    " << now_time << "   " << user.second << "\n";
            if (now_time - user.second > 30)
            {
                onlineUser.erase(user.first);
                // dbClass db(true);
                // db.AlterUserIP(user.first,"0");
                // json changePack;
                // changePack["UID"] = user.first;
                // changePack["operator"] = "offline";
                // changePack["ip"] = "-1";
                // changePack["list_no"] = userOperList.size()+1;
                // userOperList.push_back(changePack);
            }
        }
        sleep(5);
    }
}

int main(int argc, char *argv[])
{
    // if (argc >= 2)
    //     debug_Mode = string(argv[1]) == "true";
    debug_Mode = false;
    int maxClient = sizeof(infos) / sizeof(infos[0]);
    if (!debug_Mode)
    {
        pthread_t detect;
        pthread_create(&detect, NULL, DetectOnlineUser, NULL);
        pthread_detach(detect);
    }
    for (int i = 0; i < maxClient; i++)
    {
        infos[i].fd = -1;
    }
    ctcpserver tcpserver;
    if (tcpserver.initserver(atoi("8888")) == false)
    {
        perror("initserver()");
        return -1;
    }
    while (1)
    {
        struct SockInfo *pinfo;
        for (int i = 0; i < maxClient; i++)
        {
            if (infos[i].fd == -1)
            {
                pinfo = &infos[i];
                break;
            }
        }
        if (tcpserver.accept() == false)
        {
            perror("accecpt()");
            break;
        }
        pinfo->addr = tcpserver.m_clientip;
        pinfo->fd = tcpserver.m_clientfd;
        pthread_t tid;
        pthread_create(&tid, NULL, working, pinfo);
        pthread_detach(tid);
    }
    tcpserver.closelisten();
}